package com.sunlands.qdcy.tongzhuo.util;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;

@Slf4j
public class SignUtil {


    /**
     * 签名生成算法
     *
     * @param params<String,String> params 请求参数集，所有参数必须已转换为字符串类型
     * @param secret                secret 签名密钥
     * @return 签名
     * @throws IOException
     */
    public static String sign(String secret, Map<String, String[]> params) {

        String baseString = buildMapToSign(params);
        if(!StringUtils.isBlank(baseString)){
            baseString=baseString + "&" + secret;
        } else {
            baseString=secret;
        }

        log.debug("localSigStr = {}", baseString );

        byte[] bytes = null;
        // 使用MD5对待签名串求签
        try {
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            bytes = md5.digest(baseString.getBytes("UTF-8"));
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        // 将MD5输出的二进制结果转换为小写的十六进制
        StringBuilder sign = new StringBuilder();
        for (int i = 0; i < bytes.length; i++) {
            String hex = Integer.toHexString(bytes[i] & 0xFF);
            if (hex.length() == 1) {
                sign.append("0");
            }
            sign.append(hex);
        }
        String sigReturn = sign.toString().toUpperCase();
        log.info("localSig = {}", sigReturn );
        return sigReturn;
    }

    public static String signJson(String secret, String jsonStr) {

        if(StringUtils.isBlank(jsonStr)){
            jsonStr="";
        }

        String baseString = jsonStr+"&"+secret;

        log.info("localSigStr = {}", baseString );

        byte[] bytes = null;
        // 使用MD5对待签名串求签
        try {
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            bytes = md5.digest(baseString.getBytes("UTF-8"));
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        // 将MD5输出的二进制结果转换为小写的十六进制
        StringBuilder sign = new StringBuilder();
        for (int i = 0; i < bytes.length; i++) {
            String hex = Integer.toHexString(bytes[i] & 0xFF);
            if (hex.length() == 1) {
                sign.append("0");
            }
            sign.append(hex);
        }
        String sigReturn = sign.toString().toUpperCase();
        log.info("localSig = {}", sigReturn );
        return sigReturn;
    }

    public static boolean verifySign(String secret, String sign, Map<String, String[]> params) {
        return sign(secret, params).equals(sign);
    }

    public static boolean verifySignJson(String secret, String sign, String jsonStr) {
        return signJson(secret, jsonStr).equals(sign);
    }

    public static String buildSingleMapToSign(Map<String, String> paramMap) {
        Map<String, String[]> multiValueMap = new HashMap<>();
        for (Entry<String, String> entry : paramMap.entrySet()) {
            multiValueMap.put(entry.getKey(), new String[]{entry.getValue()}) ;
        }

        return buildMapToSign(multiValueMap);
    }



        /**
         * 支持参数多值
         * 1、先将 paramMap 进行key排序, 如果是多值参数, 例如type=b&type=a, 将参数值进行正序排序
         * 2、然后将排序后的 Map 转换为用&及=拼接的字符串
         *
         * @param paramMap request.getParameterMap()
         * @return String like "name1=a&name2=b
         */
    public static String buildMapToSign(Map<String, String[]> paramMap) {

        TreeMap<String, String[]> sortMap = new TreeMap<>(paramMap);
        sortMap.putAll(paramMap);

        StringBuilder builder = new StringBuilder();

        for (Entry<String, String[]> e : sortMap.entrySet()) {

            String key = e.getKey();
            String[] values = e.getValue();

            if (values == null || values.length == 0) {
                continue;
            }

            if (values.length == 1) {
                builder.append(String.format("&%s=%s", key, values[0]));
            } else if (values.length > 1) {
                Arrays.sort(values);
                for (String value : values) {
                    builder.append(String.format("&%s=%s", key, value));
                }
            }
        }

        if (builder.length() > 1) {
            builder.deleteCharAt(0);
        }

        return builder.toString();
    }

    public static void main(String[] args) {
        Map<String, String[]> paramMap = new HashMap<>();
        paramMap.put("prizeCode",new String[]{"luckywheelpay12"});

        String secret="apikey=sunlandzlcx";

        String sig = sign(secret,paramMap);
        System.out.println(sig);

        String sig2 = "bb9192dd595514103d9e49ffc68b6c57";
        System.out.println(verifySign(secret,sig2,paramMap));



    }


}
